#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kthread.h>

#include <linux/errno.h>
#include <linux/types.h>

#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>

#include <linux/delay.h>

#include <net/tcp_states.h>

#define DEFAULT_PORT	62000
#define MODULE_NAME	"TcpServer"
#define TRUE		1
#define FALSE		0
#define UNUSED		0

struct TcpServer
{
  int running;
  struct socket *sock;
  struct sockaddr_in addr;
};

struct TcpServer myServer;

static void cleanup_server(void)
{
  sock_release(myServer.sock);
  myServer.sock = NULL;
  myServer.running = FALSE;
}

// Create the server, bind and listen on DEFAULT_PORT
static int init_server(void)
{
  int err;

  memset(&myServer, 0, sizeof(myServer));
  err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &myServer.sock);
  if (err < 0)
    {
      printk(KERN_INFO MODULE_NAME": Error on sock_create. (%d)\n", err);
      return 1;
    }
  myServer.addr.sin_family = AF_INET;
  myServer.addr.sin_port = htons(DEFAULT_PORT);
  myServer.addr.sin_addr.s_addr = htonl(INADDR_ANY);
  // Binding step
  err = myServer.sock->ops->bind(myServer.sock, (struct sockaddr*)&myServer.addr, sizeof(myServer.addr));
  if (err < 0)
    {
      printk(KERN_INFO MODULE_NAME": Error on bind. (%d)\n", err);
      cleanup_server();
      return 1;
    }
  // Listening step
  err = myServer.sock->ops->listen(myServer.sock, UNUSED);
  if (err != 0)
    {
      printk(KERN_INFO MODULE_NAME": Error on listen. (%d)\n", err);
      cleanup_server();
      return 1;
    }
  printk(KERN_INFO MODULE_NAME": Server is now running on port %d\n", DEFAULT_PORT);
  myServer.running = TRUE;
  return 0;
}

static int start_server(void)
{
  int err;
  struct socket* client;

  while (myServer.running)
    {
      err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &client);
      if (err != 0)
	{
	  printk(KERN_INFO MODULE_NAME": Error on sock_create (client). (%d)\n", err);
	  cleanup_server();
	  return 1;
	}
      printk(KERN_INFO MODULE_NAME": Waiting for clients....\n");
      client->type = myServer.sock->type;
      client->ops = myServer.sock->ops;
      err = myServer.sock->ops->accept(myServer.sock, client, O_NONBLOCK);
      if (err < 0)
	{
	  printk(KERN_INFO MODULE_NAME": Error on accept. (%d)\n", err);
	  sock_release(client);
	  cleanup_server();
	  return 1;
	}
      /*
      if (client->sk->sk_state == TCP_CLOSE)
	{
	  sock_release(client);
	}
      */
      printk(KERN_INFO MODULE_NAME": Client accepted.\n");
      sock_release(client);
    }
  return 0;
}

int __init tcpserver_init(void)
{
  printk(KERN_INFO MODULE_NAME": Module loaded.\n");
  init_server();
  start_server();
  return 0;
}

void __exit tcpserver_exit(void)
{
  printk(KERN_INFO MODULE_NAME": Module unloaded.\n");
  if (myServer.running == TRUE)
    cleanup_server();
}

/* init and cleanup functions */
module_init(tcpserver_init);
module_exit(tcpserver_exit);

/* module information */
MODULE_DESCRIPTION("Simple TCP server");
MODULE_AUTHOR("Dally Richard");
MODULE_LICENSE("GPL");
